package com.proxy.common.sql;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * Created by liufish on 17/2/17.
 */
public class SqlAppendable implements Appendable {

    private final Collection<Object> segments = new LinkedList<>();

    private final Map<String, StringToken> tokenMap = new HashMap<>();

    private StringBuilder currentSegment;

    public SqlAppendable() {
        currentSegment = new StringBuilder();
        segments.add(currentSegment);
    }

    /**
     * 增加占位符.
     *
     * @param token 占位符
     * @return SQL构建器
     */
    public SqlAppendable appendToken(String token) {
        return appendToken(token, true);
    }

    /**
     * 增加占位符.
     *
     * @param token      占位符
     * @param isSetValue 是否设置占位值
     */
    public SqlAppendable appendToken(String token, boolean isSetValue) {
        StringToken stringToken;
        if (tokenMap.containsKey(token)) {
            stringToken = tokenMap.get(token);
        } else {
            stringToken = new StringToken();
            if (isSetValue) {
                stringToken.value = token;
            }
            tokenMap.put(token, stringToken);
        }
        segments.add(stringToken);
        currentSegment = new StringBuilder();
        segments.add(currentSegment);
        return this;
    }

    /**
     * 用实际的值替代占位符.
     *
     * @param originToken 占位符
     * @param newToken    实际的值
     */
    public SqlAppendable buildSQL(String originToken, String newToken) {
        if (tokenMap.containsKey(originToken)) {
            tokenMap.get(originToken).value = newToken;
        }
        return this;
    }

    /**
     * 是否包含占位符.
     *
     * @param token 占位符
     * @return true 包含 false 不包含
     */
    public boolean containsToken(final String token) {
        return tokenMap.containsKey(token);
    }

    /**
     * 生成SQL语句.
     *
     * @return SQL语句
     */
    public String toSQL() {
        StringBuilder result = new StringBuilder();
        for (Object each : segments) {
            result.append(each.toString());
        }
        return result.toString();
    }

    @Override
    public Appendable append(final CharSequence sql) throws IOException {
        currentSegment.append(sql);
        return this;
    }

    @Override
    public Appendable append(CharSequence sql, int start, int end) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Appendable append(final char c) throws IOException {
        currentSegment.append(c);
        return this;
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        for (Object each : segments) {
            if (each instanceof StringToken) {
                result.append(((StringToken) each).toToken());
            } else {
                result.append(each.toString());
            }
        }
        return result.toString();
    }

    /**
     * 复制构建器.
     *
     */
    public SqlAppendable cloneBuilder() {
        SqlAppendable result = new SqlAppendable();
        for (Object each : segments) {
            if (each instanceof StringToken) {
                StringToken token = (StringToken) each;
                StringToken newToken = new StringToken();
                newToken.value = token.value;
                result.segments.add(newToken);
                result.tokenMap.put(newToken.value, newToken);
            } else {
                result.segments.add(each);
            }
        }
        return result;
    }

    private class StringToken {

        private String value;

        public String toToken() {
            return null == value ? "" : "[Token("+value+")]";
        }

        @Override
        public String toString() {
            return null == value ? "" : value;
        }
    }
}